package com.jzo2o.foundations.service.impl;

import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.jzo2o.api.foundations.dto.response.ServeItemResDTO;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.StringUtils;
import com.jzo2o.es.core.ElasticSearchTemplate;
import com.jzo2o.foundations.constants.IndexConstants;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.mapper.ServeMapper;
import com.jzo2o.foundations.model.domain.Region;
import com.jzo2o.foundations.model.domain.Serve;
import com.jzo2o.foundations.model.domain.ServeAggregation;
import com.jzo2o.foundations.model.dto.response.ServeAggregationSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeAggregationTypeSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
import com.jzo2o.foundations.service.HomeService;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeItemService;
import com.jzo2o.foundations.service.IServeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * TODO
 *
 * @Author mr.wu
 * @Data #{DATE} #{TIME}
 */
@Service
public class HomeServiceImpl implements HomeService {
    @Autowired
    private IRegionService regionService;
    @Autowired
    private ServeMapper serveMapper;
    @Autowired
    private IServeService serveService;
    @Autowired
    private IServeItemService serveItemService;
    /**
     * 首页服务列表
     * @param regionId
     * @return
     */
    @Caching(
            cacheable = {
                @Cacheable(value = RedisConstants.CacheName.SERVE_ICON,key = "#regionId",unless = "#result.size()==0",cacheManager = RedisConstants.CacheManager.FOREVER)
                    ,
                    @Cacheable(value = RedisConstants.CacheName.SERVE_ICON,key = "#regionId",unless = "#result.size()!=0",cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES)
            }
    )
    @Override
    public List<ServeCategoryResDTO> firstPageServeList(Long regionId) {
        //1.检查区域状态是否启用
        Region region = regionService.getById(regionId);
        if(region==null || region.getActiveStatus()!=2){
            throw new ForbiddenOperationException("区域不存在或状态不对");
        }
        //2.根据城市编码查询所有服务类型和服务列表
        List<ServeCategoryResDTO> serveTypeAndServeList = serveMapper.getServeTypeAndServeList(regionId);
        if (ObjectUtil.isEmpty(serveTypeAndServeList)) {
            return Collections.emptyList();
        }
        //3.服务类型取前两个，每个类型下服务项取前4个
        Integer serveTypeSize = serveTypeAndServeList.size()>=2 ? 2:  serveTypeAndServeList.size();
        List<ServeCategoryResDTO> serveCategoryResDTOS = new ArrayList<>(serveTypeAndServeList.subList(0, serveTypeSize));
        serveCategoryResDTOS.forEach(serveType->{
            List<ServeSimpleResDTO> serveResDTOList = serveType.getServeResDTOList();
            Integer serveSize = serveResDTOList.size()>=4 ? 4 : serveResDTOList.size();

            List<ServeSimpleResDTO> serveSimpleResDTOS = new ArrayList<>(serveResDTOList.subList(0, serveSize));
            serveResDTOList = serveResDTOList.subList(0,serveSize);
            serveType.setServeResDTOList(serveSimpleResDTOS);
        });
        return serveCategoryResDTOS;
    }
    /**
     *  服务类型列表缓存
     * @param regionId
     * @return
     */
    @Override
    @Caching(
            cacheable = {
                    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE,key = "#regionId",unless = "#result.size()==0",cacheManager = RedisConstants.CacheManager.FOREVER)
                    ,
                    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE,key = "#regionId",unless = "#result.size()!=0",cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES)
            }
    )
    public List<ServeAggregationTypeSimpleResDTO> serveTypeList(Long regionId) {
        //判断regionId是否为空
        if(regionId==null){
            throw new BadRequestException("参数非法");
        }
        //检查区域状态是否启用
        Region region = regionService.getById(regionId);
        if(region==null || region.getActiveStatus()!=2){
            throw new ForbiddenOperationException("区域不存在或状态不对");
        }
        //获取服务类型
       List<ServeAggregationTypeSimpleResDTO> list = serveMapper.queryServeTypeList(regionId);
       //去重
        List<ServeAggregationTypeSimpleResDTO> ServeTypeList = list.stream().distinct().collect(Collectors.toList());
        return ServeTypeList;
    }
    /**
     * 查询热门服务列表并缓存
     * @param regionId
     * @return
     */
    @Caching(
            cacheable = {
                    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE,key = "#regionId",unless = "#result.size()==0",cacheManager = RedisConstants.CacheManager.FOREVER)
                    ,
                    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE,key = "#regionId",unless = "#result.size()!=0",cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES)
            }
    )
    @Override
    public List<ServeAggregationSimpleResDTO> hotServeList(Long regionId) {
        //判断regionId是否为空
        if(regionId==null){
            throw new BadRequestException("参数非法");
        }
        //检查区域状态是否启用
        Region region = regionService.getById(regionId);
        if(region==null || region.getActiveStatus()!=2){
            throw new ForbiddenOperationException("区域不存在或状态不对");
        }
        //获取服务类型
        List<ServeAggregationSimpleResDTO> list = serveMapper.queryHotServeList(regionId);
        return list;
    }
    /**
     * 根据id查询服务详情并缓存
     * @param id
     * @return
     */
    @Override
    public ServeAggregationSimpleResDTO ServeDetail(Long id) {
        //判断服务ID是否为空
        if(id==null){
            throw new BadRequestException("参数非法");
        }
        //根据id查询服务信息的方法
        Serve serve = serveService.queryServeByIdCache(id);
        if(serve==null){
            throw new DBException("未找到该服务");
        }
        ServeItemResDTO serveItemResDTO = serveItemService.queryServeItemAndTypeById(serve.getServeItemId());
        if(serveItemResDTO==null){
            throw new DBException("未找到该服务项");
        }
        ServeAggregationSimpleResDTO dto = new ServeAggregationSimpleResDTO();
        dto.setId(id);
        dto.setCityCode(serve.getCityCode());
        dto.setDetailImg(serveItemResDTO.getDetailImg());
        dto.setPrice(serve.getPrice());
        dto.setServeItemId(serveItemResDTO.getId());
        dto.setServeItemImg(serveItemResDTO.getImg());
        dto.setServeItemName(serveItemResDTO.getName());
        dto.setUnit(serveItemResDTO.getUnit());
        return dto;
    }

    @Resource
    private ElasticSearchTemplate elasticSearchTemplate;

    @Override
    public List<ServeSimpleResDTO> search(String cityCode, String keyword, Long serveTypeId) {
        SearchRequest.Builder searchRequestBuilder = new SearchRequest.Builder();
        //1. 设置索引库名
        searchRequestBuilder.index(IndexConstants.SERVE);

        //2. 设置查询条件： 布尔组合查询
        searchRequestBuilder.query(query->query.bool(bool->{

            //必须的查询条件：根据城市编码term查询
            bool.must(must-> must.term(term->term.field("city_code").value(cityCode)));

            //可能的筛选条件：根据查询关键词multi_match查询
            if(StringUtils.isNotBlank(keyword)){
                bool.filter(filter->filter.multiMatch(multi->multi.fields("serve_item_name","serve_type_name").query(keyword)));
            }

            //可能的筛选条件：根据服务类型id精确查询
            if(serveTypeId!=null) {
                bool.filter(filter->filter.term(term->term.field("serve_type_id").value(serveTypeId)));
            }

            //返回bool对象
            return bool;
        }));

        //3. 设置排序：根据序号升序
        searchRequestBuilder.sort(x->x.field(y->y.field("serve_item_sort_num").order(SortOrder.Asc)));

        //4. 执行查询
        SearchResponse<ServeAggregation> searchResponse = elasticSearchTemplate.opsForDoc().search(searchRequestBuilder.build(), ServeAggregation.class);

        //5. 解析响应结果
        List<Hit<ServeAggregation>> hitList = searchResponse.hits().hits();

        List<ServeSimpleResDTO> resultList = new ArrayList<>();
        if(CollUtils.isNotEmpty(hitList)){
            for (Hit<ServeAggregation> hit : hitList) {
                ServeAggregation aggregation = hit.source();
                ServeSimpleResDTO dto = BeanUtils.copyBean(aggregation, ServeSimpleResDTO.class);
                resultList.add(dto);
            }
        }
        return resultList;
    }
}
